package p01_BeanFactory和ApplicationContext;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * ApplicationContext接口是BeanFactory子接口，所以天然具有BeanFactory的功能
 * 同时该接口还继承了其他接口，因此该接口扩展了额外功能
 * 四个额外父接口：
 *  1.MessageSource: 处理国际化资源的能力
 *  2.ResourcePatternResolver: 利用通配符匹配资源(硬盘上的文件)的能力
 *  3.ApplicationEventPublisher: 事件发布能力
 *  4.EnvironmentCapable: 处理Spring的环境信息的能力
 *
 * ApplicationContext不仅是继承了BeanFactory接口，也组合了BeanFactory并扩展(继承其他接口)了功能
 */
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class _2_ApplicationContext {

    public static void main(String[] args) throws IOException {
        /**
         * 下面演示了ApplicationContext拓展的功能
         */
        ConfigurableApplicationContext context = SpringApplication.run(_2_ApplicationContext.class);
        //1.国际化 ===> String hi = context.getMessage("hi", null, Locale.CHINA);

        /**
         * 2.根据通配符获取资源，classpath:xxx(当前类路径下找到指定资源),classpath*:xxx(类路径下找到所有指定资源),file:xxx(磁盘上找资源)
         */
        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }
        /**
         * 3.获取环境变量信息,既可以获取操作系统的环境变量，又可以获取配置文件中的变量
         */
        String javaHome = context.getEnvironment().getProperty("JAVA_HOME");
        System.out.println(javaHome);

        /**
         * 4.发布事件
         *  发布事件需要有事件对象，ApplicationEvent子类
         *  监听器监听该事件，容器中的任何bean都可以作为监听器,监听方法需要EventListener注解
         *  其他地方可以直接注入ApplicationEventPublisher获取容器对象
         *  事件发布于监听的原理最后两章会介绍
         */
        context.publishEvent(new MyEvent(context));
        context.close();
    }

    /**
     * 事件对象
     */
    static class MyEvent extends ApplicationEvent {
        /**
         * @param source 事件源，谁发的事件
         */
        public MyEvent(Object source) {super(source);}
    }

    @Component
    static class MyListener {
        /**
         * 只监听MyEvent类型的事件
         * @param event 监听的事件类型
         */
        @EventListener
        public void listen(MyEvent event) {
            System.out.println("监听到了事件发生..." + event);
        }
    }
}
